/**
 * @file wiz_socket.h
 * @brief wizchip 套接字基于FreeRTOS封装
 * @author wangh (wanghuan3037@fiberhome.com)
 * @version 1.0
 * @date 2020-11-09
 * @copyright Copyright (c) 2020  烽火通信
 */
#ifndef __WIZ_SOCKET_H
#define __WIZ_SOCKET_H 
#include "w5500.h"
#include "wizchip_socket.h"
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "timers.h"


#define WIZ_SOCK_ERROR          (-50)
#define SOCKERR_INIT_PHY        (WIZ_SOCK_ERROR - 1)    ///< not init or phy lick off
#define SOCKERR_ALLOC_SOCK      (WIZ_SOCK_ERROR - 2)    ///< alloc_socket failed
#define SOCKERR_GET_SOCK        (WIZ_SOCK_ERROR - 3)    ///< wiz_get_socket failed
#define SOCKERR_NO_MEM          (WIZ_SOCK_ERROR - 4)    ///< 内存不足
#define SOCKERR_PARAM           (WIZ_SOCK_ERROR - 5)    ///< 非法入参


#define WIZ_SOCKET_MAGIC    0x3120  ///< socket 资源分配使用标记字

/** @brief 套接字结构体 */
typedef struct wiz_socket_s
{
    uint32_t magic;     ///< socket 使用标记字

    uint8_t socket;     ///< socket 号
    uint16_t port;      ///< 本地端口
    uint8_t protocol;   ///< socket (TCP, UDP or RAW)
    // uint8_t state;      ///< socket 状态

    SemaphoreHandle_t recv_notice;  ///< 接收通知信号量
    SemaphoreHandle_t recv_lock;    ///< 接收函数锁

    TimerHandle_t tcps_tmr;         ///< TCP维护服务器定时器

    // uint32_t recv_timeout;  ///< 接收超时时间（ms）
    // uint32_t send_timeout;  ///< 发送超时时间（ms）

    uint8_t remote_ip[4];   ///< 远程IP
    uint16_t remote_port;   ///< 远程端口
    
} wiz_socket_t;


/**
 * @brief 创建套接字
 * @param[in]  protocol 协议 @ref Sn_MR_TCP @ref Sn_MR_UDP
 * @param[in]  port     端口号
 * @param[in]  flag     套接字标志(0 Sn_MR_ND)
 * @return int8_t 
 * - @b Sucess : 套接字号（0~7） \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_ALLOC_SOCK - 套接字分配失败
 * - @ref SOCKERR_SOCKSTATUS - sock状态异常
 * - @ref SOCKERR_SOCKMODE - sock模式不支持
 * - @ref SOCKERR_SOCKINIT - IP未设置
 */
int8_t wiz_socket( uint8_t protocol, uint16_t port, uint8_t flag );

/**
 * @brief 关闭套接字,释放资源
 * @param[in]  socket   socket号
 * @return int8_t 
 * - @b Sucess : SOCK_OK \n
 * - @b Fail
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 */
int8_t wiz_close(uint8_t socket);

/**
 * @brief 启动TCP服务器 \n
 * 维护TCP套接字资源，维护TCP连接
 * @param[in]  port     服务器端口
 * @return int8_t 
 * - @b Sucess : socket号 \n
 * - @b Fail : @ref wiz_socket \n
 * - @ref SOCKERR_NO_MEM - 内存不足
 */
int8_t wiz_tcpServer_start( uint16_t port );

/**
 * @brief 套接字连接（only for TCP）
 * @param[in]  socket   socket号
 * @param[in]  addr     目的IP
 * @param[in]  port     目的端口
 * @return int8_t 
 * - @b Sucess : SOCK_OK \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKINIT - 不是INIT状态
 */
int8_t wiz_connect(uint8_t socket, uint8_t * addr, uint16_t port);

/**
 * @brief 套接字断开连接（only for TCP）
 * @param[in]  socket   socket号
 * @return int8_t 
 * - @b Sucess : SOCK_OK \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKSTATUS - 不是 SOCK_ESTABLISHED 状态
 */
int8_t wiz_disconnect(uint8_t socket);

/**
 * @brief 数据流套接字发送
 * @param[in]  socket   socket号
 * @param[in]  buf      发送缓存
 * @param[in]  len      发送长度
 * @return int32_t 
 * - @b Sucess : 实际发送长度 \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_PARAM - 错误入参
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKSTATUS - 非 SOCK_ESTABLISHED 状态
 * - @ref SOCKERR_SOCKCLOSED - 套接字非法关闭
 * - @ref SOCK_BUSY - 套接字忙
 * - @ref SOCKERR_TIMEOUT - 发送超时
 */
int32_t wiz_send(uint8_t socket, uint8_t * buf, uint16_t len);

/**
 * @brief 数据流套接字接收
 * @param[in]  socket   socket号
 * @param[in]  buf      接收缓存
 * @param[in]  len      接收长度
 * @param[in]  timeout  接收超时时间（ms）
 * - 0 立即返回
 * - portMAX_DELAY 一直阻塞
 * @return int32_t 
 * - @b Sucess : 实际接收的长度 \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_PARAM - 错误入参
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKSTATUS - 非 SOCK_ESTABLISHED 状态
 * - @ref SOCKERR_SOCKCLOSED - 套接字非法关闭
 * - @ref SOCK_BUSY - 套接字忙
 * - @ref SOCKERR_TIMEOUT - 接收超时
 */
int32_t wiz_recv(uint8_t socket, uint8_t * buf, uint16_t len, uint32_t timeout);

/**
 * @brief 数据报套接字发送
 * @param[in]  socket   socket号
 * @param[in]  buf      发送缓存
 * @param[in]  len      发送长度
 * @param[in]  addr     目标IP
 * @param[in]  port     目标端口
 * @return int32_t 
 * - @b Sucess : 实际发送长度 \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKSTATUS - 非 SOCK_UDP 状态
 * - @ref SOCKERR_SOCKCLOSED - 套接字非法关闭
 * - @ref SOCK_BUSY - 套接字忙
 * - @ref SOCKERR_TIMEOUT - 发送超时
 */
int32_t wiz_sendto(uint8_t socket, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t port);

/**
 * @brief 数据报套接字接收
 * @param[in]  socket   socket号
 * @param[in]  buf      接收缓存
 * @param[in]  len      接收长度
 * @param[out] addr     远程ip地址
 * @param[out] port     远程端口
 * @param[in]  timeout  接收超时时间（ms）
 * - 0 立即返回
 * - portMAX_DELAY 一直阻塞
 * @return int32_t 
 * - @b Sucess : 实际接收的长度 \n
 * - @b Fail
 * - @ref SOCKERR_INIT_PHY - phy断开或未初始化成功
 * - @ref SOCKERR_PARAM - 错误入参
 * - @ref SOCKERR_GET_SOCK - 获取套接字资源失败
 * - @ref SOCKERR_SOCKSTATUS - 非 SOCK_UDP 状态
 * - @ref SOCKERR_SOCKCLOSED - 套接字非法关闭
 * - @ref SOCK_BUSY - 套接字忙
 * - @ref SOCKERR_TIMEOUT - 接收超时
 */
int32_t wiz_recvfrom(uint8_t socket, uint8_t * buf, uint16_t len, uint8_t * addr, uint16_t *port, uint32_t timeout);

#if WIZ_USING_DNS
/**
 * @brief 域名解析
 * @param[in]  name         域名
 * @param[in]  ip_from_dns  解析IP
 * @return int8_t 
 * - @b Sucess : 0 \n
 * - @b Fail : -1
 */
int8_t wiz_gethostbyname(const char *name, uint8_t * ip_from_dns);
#endif

#endif	 // __WIZ_SOCKET_H 

/*********** (C) COPYRIGHT 2020 FiberHome *****END OF FILE****/
